/*
 * Copyright (C) 2022 by Intel Corporation
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdint.h>
#include <stdlib.h>

#include <benchmark/benchmark.h>
#include <xmmintrin.h>

#include "avx2_min_max.h"
#include "mmx_min_max.h"

static void init_sources(int16_t *in, int len)
{
	for (int i = 0; i < len; i++)
		in[i] = (int16_t)i - (len / 2);

	for (int i = 0; i < len; i++) {
		int x = rand() % len;
		int y = rand() % len;
		int16_t tmp = in[x];
		in[x] = in[y];
		in[y] = tmp;
	}
}

static void BM_mmx_min_max(benchmark::State &state)
{
	min_max res;
	int len = state.range(0);
	int16_t *in = (int16_t *)_mm_malloc(sizeof(uint16_t) * len, 32);

	init_sources(in, len);
	for (auto _ : state) {
		mmx_min_max(in, &res, len);
	}

	state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(len) *
				int64_t(sizeof(*in)));

	_mm_free(in);
}

static void BM_avx2_min_max(benchmark::State &state)
{
	min_max res;
	int len = state.range(0);
	int16_t *in = (int16_t *)_mm_malloc(sizeof(uint16_t) * len, 32);

	init_sources(in, len);
	for (auto _ : state) {
		avx2_min_max(in, &res, len);
	}

	state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(len) *
				int64_t(sizeof(*in)));

	_mm_free(in);
}

BENCHMARK(BM_mmx_min_max)
    ->Arg(1 << 8)
    ->Arg(1 << 10)
    ->Arg(1 << 12)
    ->Arg(1 << 14)
    ->Arg(1 << 16)
    ->Arg(1 << 18);
BENCHMARK(BM_avx2_min_max)
    ->Arg(1 << 8)
    ->Arg(1 << 10)
    ->Arg(1 << 12)
    ->Arg(1 << 14)
    ->Arg(1 << 16)
    ->Arg(1 << 18);
BENCHMARK_MAIN();
